﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
#if !WINDOWS_PHONE


#endif

namespace DARE
{
    [AttrTypeDependentSerializable(typeof(DARE.Save.DataStructures.CCylinderModelData))]
    public class CCylinderModel : CBasicModel
    {

    #region fields

        private int m_slices = 20;

    #endregion

    #region properties

        public override int Slices
        {
            get { return m_slices; }
            set 
            {
                if ((value != m_slices) && (value >= 4))
                {
                    m_slices = value;
                    SetupVertices();
                    CreateVertexBuffer();
                }
            }
        }

    #endregion

    #region ctor

        public CCylinderModel() : 
            base()
        {
            Initalize();
        }

        public CCylinderModel(string name) : 
            base(name)
        {
            Initalize();
        }

        public CCylinderModel(float length, float diameter) : 
            base(diameter, length, diameter)
        {
            Initalize();
        }

        public CCylinderModel(string name, float length, float diameter) : 
            base(name, diameter, length, diameter)
        {
            Initalize();
        }

        public CCylinderModel(float length, float baseDiameter, float topDiameter) :
            base(baseDiameter, length, topDiameter)
        {
            Initalize();
        }

        public CCylinderModel(string name, float length, float baseDiameter, float topDiameter) :
            base(name, baseDiameter, length, topDiameter)
        {
            Initalize();
        }

        private void Initalize()
        {
            CullMode = CullMode.None;
            m_orientation = Matrix.CreateRotationX(MathHelper.PiOver2);
            SetupVertices();
            CreateVertexBuffer();
        }

        public override AModel Clone()
        {
            CCylinderModel clone = new CCylinderModel(m_name, m_size.Y, m_size.X);

            base.CopyPropertiesTo(clone);
            return clone;
        }

    #endregion

    #region setup

        protected void SetupVertices()
        {
            m_size /= 2.0f;
#if WINDOWS_PHONE
            m_vertices = new VertexPositionNormalTexture[m_slices * 12];
#else
            m_vertices = new VertexPositionNormalTextureTangentBinormal[m_slices * 12];
#endif

            // points definition and normal
            Vector3 topCenter = Vector3.UnitY * m_size.Y;
            Vector3 topFirst = Vector3.Zero;
            Vector3 topSecond = Vector3.Zero;
            Vector3 bottomCenter = -Vector3.UnitY * m_size.Y;
            Vector3 bottomFirst = Vector3.Zero;
            Vector3 bottomSecond = Vector3.Zero;
            Vector3 normal = Vector3.Zero;
            Vector3 normal2 = Vector3.Zero;

            // as needed to create the vertices
            float a = 0.0f;
            float an = 0.0f;

#if WINDOWS_PHONE
            // cylinder creation
            for (int i = 0; i < m_slices; ++i)
            {
                // calculate the angles
                a = ((float)i) * (MathHelper.TwoPi / m_slices);
                an = ((float)i + 1) * (MathHelper.TwoPi / m_slices);

                // calculate the points and the normal with the new angles
                topFirst = new Vector3(m_size.X * (float)Math.Cos(a), m_size.Y, m_size.X * (float)Math.Sin(a));
                topSecond = new Vector3(m_size.X * (float)Math.Cos(an), m_size.Y, m_size.X * (float)Math.Sin(an));
                bottomFirst = new Vector3(m_size.Z * (float)Math.Cos(a), -m_size.Y, m_size.Z * (float)Math.Sin(a));
                bottomSecond = new Vector3(m_size.Z * (float)Math.Cos(an), -m_size.Y, m_size.Z * (float)Math.Sin(an));
                normal = new Vector3((float)Math.Cos(a), 0, (float)Math.Sin(a));
                normal.Normalize();
                normal2 = new Vector3((float)Math.Cos(an), 0, (float)Math.Sign(an));
                normal2.Normalize();

                // top face
                m_vertices[i * 12 + 0] = new VertexPositionNormalTexture(topCenter, Vector3.UnitY, Vector2.Zero);
                m_vertices[i * 12 + 1] = new VertexPositionNormalTexture(topFirst, Vector3.UnitY, Vector2.Zero);
                m_vertices[i * 12 + 2] = new VertexPositionNormalTexture(topSecond, Vector3.UnitY, Vector2.Zero);

                // side face
                // top triangle
                m_vertices[i * 12 + 3] = new VertexPositionNormalTexture(bottomFirst, bottomFirst + Vector3.UnitY * m_size.Y, Vector2.Zero);
                m_vertices[i * 12 + 4] = new VertexPositionNormalTexture(topSecond, topSecond - Vector3.UnitY * m_size.Y, Vector2.Zero);
                m_vertices[i * 12 + 5] = new VertexPositionNormalTexture(topFirst, topFirst - Vector3.UnitY * m_size.Y, Vector2.Zero);
                // bottom triangle
                m_vertices[i * 12 + 6] = new VertexPositionNormalTexture(bottomSecond, bottomSecond + Vector3.UnitY * m_size.Y, Vector2.Zero);
                m_vertices[i * 12 + 7] = new VertexPositionNormalTexture(topSecond, topSecond - Vector3.UnitY * m_size.Y, Vector2.Zero);
                m_vertices[i * 12 + 8] = new VertexPositionNormalTexture(bottomFirst, bottomFirst + Vector3.UnitY * m_size.Y, Vector2.Zero);

                // bottom face
                m_vertices[i * 12 + 9] = new VertexPositionNormalTexture(bottomSecond, -Vector3.UnitY, Vector2.Zero);
                m_vertices[i * 12 + 10] = new VertexPositionNormalTexture(bottomFirst, -Vector3.UnitY, Vector2.Zero);
                m_vertices[i * 12 + 11] = new VertexPositionNormalTexture(bottomCenter, -Vector3.UnitY, Vector2.Zero);

                m_vertices[i * 12 + 0].Normal = Vector3.UnitY;
                m_vertices[i * 12 + 1].Normal = Vector3.UnitY;
                m_vertices[i * 12 + 2].Normal = Vector3.UnitY;
                m_vertices[i * 12 + 9].Normal = -Vector3.UnitY;
                m_vertices[i * 12 + 10].Normal = -Vector3.UnitY;
                m_vertices[i * 12 + 11].Normal = -Vector3.UnitY;
            }
#else
            // cylinder creation
            for (int i = 0; i < m_slices; ++i)
            {
                // calculate the angles
                a = ((float)i) * (MathHelper.TwoPi / m_slices);
                an = ((float)i + 1) * (MathHelper.TwoPi / m_slices);

                // calculate the points and the normal with the new angles
                topFirst = new Vector3(m_size.X * (float)Math.Cos(a), m_size.Y, m_size.X * (float)Math.Sin(a));
                topSecond = new Vector3(m_size.X * (float)Math.Cos(an), m_size.Y, m_size.X * (float)Math.Sin(an));
                bottomFirst = new Vector3(m_size.Z * (float)Math.Cos(a), -m_size.Y, m_size.Z * (float)Math.Sin(a));
                bottomSecond = new Vector3(m_size.Z * (float)Math.Cos(an), -m_size.Y, m_size.Z * (float)Math.Sin(an));
                normal = new Vector3((float)Math.Cos(a), 0, (float)Math.Sin(a));
                normal.Normalize();
                normal2 = new Vector3((float)Math.Cos(an), 0, (float)Math.Sign(an));
                normal2.Normalize();

                // top face
                m_vertices[i * 12 + 0] = new VertexPositionNormalTextureTangentBinormal(topCenter, Vector3.UnitY, Vector2.Zero);
                m_vertices[i * 12 + 1] = new VertexPositionNormalTextureTangentBinormal(topFirst, Vector3.UnitY, Vector2.Zero);
                m_vertices[i * 12 + 2] = new VertexPositionNormalTextureTangentBinormal(topSecond, Vector3.UnitY, Vector2.Zero);

                // side face
                // top triangle
                m_vertices[i * 12 + 3] = new VertexPositionNormalTextureTangentBinormal(bottomFirst, bottomFirst + Vector3.UnitY * m_size.Y, Vector2.Zero);
                m_vertices[i * 12 + 4] = new VertexPositionNormalTextureTangentBinormal(topSecond, topSecond - Vector3.UnitY * m_size.Y, Vector2.Zero);
                m_vertices[i * 12 + 5] = new VertexPositionNormalTextureTangentBinormal(topFirst, topFirst - Vector3.UnitY * m_size.Y, Vector2.Zero);
                // bottom triangle
                m_vertices[i * 12 + 6] = new VertexPositionNormalTextureTangentBinormal(bottomSecond, bottomSecond + Vector3.UnitY * m_size.Y, Vector2.Zero);
                m_vertices[i * 12 + 7] = new VertexPositionNormalTextureTangentBinormal(topSecond, topSecond - Vector3.UnitY * m_size.Y, Vector2.Zero);
                m_vertices[i * 12 + 8] = new VertexPositionNormalTextureTangentBinormal(bottomFirst, bottomFirst + Vector3.UnitY * m_size.Y, Vector2.Zero);

                // bottom face
                m_vertices[i * 12 + 9] = new VertexPositionNormalTextureTangentBinormal(bottomSecond, -Vector3.UnitY, Vector2.Zero);
                m_vertices[i * 12 + 10] = new VertexPositionNormalTextureTangentBinormal(bottomFirst, -Vector3.UnitY, Vector2.Zero);
                m_vertices[i * 12 + 11] = new VertexPositionNormalTextureTangentBinormal(bottomCenter, -Vector3.UnitY, Vector2.Zero);

                m_vertices[i * 12 + 0].Normal = Vector3.UnitY;
                m_vertices[i * 12 + 1].Normal = Vector3.UnitY;
                m_vertices[i * 12 + 2].Normal = Vector3.UnitY;
                m_vertices[i * 12 + 9].Normal = -Vector3.UnitY;
                m_vertices[i * 12 + 10].Normal = -Vector3.UnitY;
                m_vertices[i * 12 + 11].Normal = -Vector3.UnitY;
            }
#endif
            // normalize the normals
            for (int i = 0; i < m_vertices.Length; ++i)
                m_vertices[i].Normal.Normalize();

            m_size *= 2.0f;
          
            //m_orientation = Matrix.CreateRotationX(MathHelper.Pi);
        }

    #endregion

    }
}
